#include "ThreadPool.h"
#include "ThreadPoolWorkerThread.h"
#include "suHttpParser.h"
#include "cnet.h"

#include "OldDreamTools\Win32Tools\IOBuffer.h"
#include "OldDreamTools\Win32Tools\SocketServer.h"
#include "OldDreamTools\Win32Tools\Exception.h"
#include "OldDreamTools\Win32Tools\Utils.h"
#include "OldDreamTools\Win32Tools\tstring.h"
#include "OldDreamTools\Win32Tools\SocketAddress.h"


#include <iostream>//--test code



///////////////////////////////////////////////////////////////////////////////
// Using directives
///////////////////////////////////////////////////////////////////////////////

using OldDreamTools::Win32::CIOBuffer;
using OldDreamTools::Win32::BasePackage;
using OldDreamTools::Win32::CIOCompletionPort;
using OldDreamTools::Win32::CEvent;
using OldDreamTools::Win32::CSocketServer::Socket;
using OldDreamTools::Win32::CException;
using OldDreamTools::Win32::Output;
using OldDreamTools::Win32::_tstring;
using OldDreamTools::Win32::CSocketAddress;
using OldDreamTools::Win32::ToString;
using OldDreamTools::Win32::MakeErrorPackage;
using OldDreamTools::Win32::MakeErrorData;

///////////////////////////////////////////////////////////////////////////////
// Local per connection data
///////////////////////////////////////////////////////////////////////////////

class CPerConnectionData
{
   public :

      explicit CPerConnectionData(
         const _tstring &address)
         :  m_numUses(0),
            m_address(address)
      {
      }

      void UseConnection()
      {
         //lint -e{534} Ignoring return value of function
         ::InterlockedIncrement(&m_numUses);
      }

      _tstring GetConnectionDetails() const
      {
         return m_address + _T(" - ") + ToString(m_numUses);
      }

   private :

      long m_numUses;

      const _tstring m_address;

      // No copies, do not implement
      CPerConnectionData(const CPerConnectionData &rhs);
      CPerConnectionData &operator=(const CPerConnectionData &rhs);
};


///////////////////////////////////////////////////////////////////////////////
// CThreadPoolWorkerThread
///////////////////////////////////////////////////////////////////////////////

CThreadPoolWorkerThread::CThreadPoolWorkerThread(
   CIOCompletionPort &iocp,
   CEvent &messageReceivedEvent,
   OldDreamTools::Win32::CThreadPool &pool)
   :  OldDreamTools::Win32::CThreadPool::WorkerThread(iocp, messageReceivedEvent, pool)
{
}

bool CThreadPoolWorkerThread::Initialise()
{
   Output(_T("CThreadPoolWorkerThread::Initialise"));
 /*  m_hAppDll    = NULL;
   InitContext();*/

   return true;
}

void CThreadPoolWorkerThread::InitContext()
{	
    m_nAppID   = 0;
	m_nInLen   = CServerSet::gOnly().GetInBufSize();
	m_nOutLen  = CServerSet::gOnly().GetOutBufSize();
	m_pInData  = NULL;
	m_pOutData = NULL;
}

void CThreadPoolWorkerThread::ClearContext()
{
	if (m_hAppDll != NULL)
	{
		FreeLibrary(m_hAppDll);
	}

	//delete m_pContext;
	//delete [] m_pOutData;
	//delete [] m_pInData;
}
void CThreadPoolWorkerThread::Process(
   ULONG_PTR completionKey,
   DWORD operation,
   OVERLAPPED *pOverlapped)
{
   Socket *pSocket = reinterpret_cast<Socket *>(completionKey);
   CIOBuffer *pBuffer = static_cast<CIOBuffer *>(pOverlapped);

   try
   {
      switch(operation)
      {
         case CThreadPool::ConnectionEstablished :

            OnConnectionEstablished(pSocket, pBuffer);

         break;

         case CThreadPool::ReadCompleted :

            ProcessMessage(pSocket, pBuffer);

         break;

         case CThreadPool::ConnectionClosing :

            OnConnectionClosing(pSocket);

         break;

         case CThreadPool::ConnectionClosed :

            OnConnectionClosed(pSocket);

         break;

         default :

            // do nothing

         break;
      }
   }
   catch(const CException &e)
   {
      Output(_T("Process - Exception - ") + e.GetWhere() + _T(" - ") + e.GetMessage());
	  std::string strMsg = e.GetWhere() + _T(" - ") + e.GetMessage();
	  pSocket->Write(strMsg.c_str(),strMsg.size());
      pSocket->Shutdown();
   }
  catch(...)
   {
      Output(_T("Process - Unexpected exception"));
	  std::string strMsg = _T("Process - Unexpected exception");
	  pSocket->Write(strMsg.c_str(),strMsg.size());
	  pSocket->Shutdown();
   }

   pSocket->Release();

   if (pBuffer)
   {
      pBuffer->Release();
   }
}

void CThreadPoolWorkerThread::Shutdown()
{
   Output(_T("CThreadPoolWorkerThread::Shutdown"));
   ClearContext();

}

void CThreadPoolWorkerThread::OnConnectionEstablished(
   Socket *pSocket,
   CIOBuffer *pAddress)
{
   USES_CONVERSION;

   //lint -e{826} Suspicious pointer-to-pointer conversion (area too small)
   CSocketAddress address(reinterpret_cast<const sockaddr*>(pAddress->GetBuffer()));

   CPerConnectionData *pData = new CPerConnectionData(address.GetAsString());

   // Allocate per connection data

   pSocket->SetUserPtr(pData);
   Output(pData->GetConnectionDetails().c_str());

   //!Here can send "connect successful" information.
   pSocket->Read();

   //lint -e{429} Custodial pointer 'pData' has not been freed or returned
   // ownership passed to pSocket

   //lint -e{1762} Member function could be made const

   //lint -e{818} Pointer parameter 'pAddress' (line 215) could be declared as pointing to const
}

void CThreadPoolWorkerThread::OnConnectionClosing(
   Socket *pSocket)
{
   // We'll perform a lingering close on this thread

   pSocket->Close();

   //lint -e{1762} Member function could be made const
}

void CThreadPoolWorkerThread::OnConnectionClosed(
   Socket *pSocket)
{
   // release per connection data

   CPerConnectionData *pData = reinterpret_cast<CPerConnectionData*>(pSocket->GetUserPtr());

   pSocket->SetUserData(0);

   delete pData;

   //lint -e{1762} Member function could be made const
}



TCP_MsgType  CThreadPoolWorkerThread::getTCPMsgType(string & netCommand)
{
	if(netCommand.substr(0,3) == "GET")
	{
		return MSGTYPE_GET;
	}
	else if(netCommand.substr(0,6) == "<CNET>")
	{
		return MSGTYPE_CNET;
	}
	else if(netCommand.substr(0,4) == "POST")
	{
		return MSGTYPE_POST;
	}
	else
	{
		return MSGTYPE_UNKNOW;
	}
}

Proc_status  CThreadPoolWorkerThread::handMsgPost(string & command,suHttpParser &httpParser)
{
	if(!httpParser.isValidPost(command))
		return NOMSGTOSEND;

	if(httpParser.getSoapAction(command))
	{
		suService* pService = CServerSet::gOnly().GetModule(httpParser.m_requestFilename);
		if (pService!=NULL)
		{
			httpParser.genPostResonse(pService->run(httpParser.m_requestFilename,httpParser.m_postParameter));
			return PostResponseToSend;
		}
		else 
		{
			return NOMSGTOSEND;
		}
	}
	else
	{
		return NOMSGTOSEND;
	}

}

Proc_status  CThreadPoolWorkerThread::handMsgGet(string & command,suHttpParser & httpParser)
{
	//Only the format like "/ServicesName?xsl" can be identified.
	//suHttpParser httpParser;
	if(!httpParser.isValidGet(command))
	{
		return NOMSGTOSEND;
	}
	if(httpParser.genHttpGetResponse(command))
	{
		return GetResponseToSend;
	}
	else 
	{
		if (httpParser.m_getParameter == "WSDL")
		{
				suService* pService = CServerSet::gOnly().GetModule(httpParser.m_requestFilename);
				if (pService != NULL)
				{
					httpParser.genWsdlResponse(pService->getWsdl());
					return GetResponseToSend;
				}
				else
				{
					return NOMSGTOSEND;
				}
		}
		else
		{
			return NOMSGTOSEND;
		}
	}
}

void CThreadPoolWorkerThread::ProcessMessage(Socket *pSocket,/*const*/ CIOBuffer *pBuffer) /*const*/
{
	string command = reinterpret_cast<const char*>(pBuffer->GetBuffer());
	string response;
	suHttpParser httpParser;
	TCP_MsgType msgType = getTCPMsgType(command);
	Proc_status ProcStatus;
	CNETManager  cm;
	CPerConnectionData *pData = reinterpret_cast<CPerConnectionData*>(pSocket->GetUserPtr());
	pData->UseConnection();
	USES_CONVERSION;
	switch(msgType)
	{
		case MSGTYPE_GET:
			ProcStatus= handMsgGet(command, httpParser);
		break;
		case MSGTYPE_POST:
			ProcStatus =handMsgPost(command, httpParser);
			break;
	//	case MSGTYPE_CNET:
		//	ProcStatus= cm.handMsgCNET(command,response);
			break;
		case MSGTYPE_UNKNOW:
			break;
		default:
			break;
	}



	switch(ProcStatus)
	{
		case PostResponseToSend:
		case GetResponseToSend:
			pSocket->Write(httpParser.m_strResponse.c_str(), httpParser.m_strResponse.length());
			break;
	//	case AwardToSend:
		//	pSocket->Write(response.c_str(), response.length());
		//	break;

	}
	/*else if(cmd == "CHECK")
	{
		std::string response("-Got CHECK, we know what you mean, bye... ");

		response = response + T2A(const_cast<TCHAR*>(pData->GetConnectionDetails().c_str())) + "\r\n";

		pSocket->Write(response.c_str(), response.length());
		pSocket->Shutdown();
	}
	else if(cmd == "UNKNOWN")
	{
		std::string response("-Err, we don't know what you mean, bye... ");

		response = response + T2A(const_cast<TCHAR*>(pData->GetConnectionDetails().c_str())) + "\r\n";

		pSocket->Write(response.c_str(), response.length());
		pSocket->Shutdown();
	}
    */
}

///////////////////////////////////////////////////////////////////////////////
// Lint options
//
//lint -restore
//
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// End of file...
///////////////////////////////////////////////////////////////////////////////
